﻿using System.Text;

namespace SocketCore.Common.Message;

public class MessageProtocol
{
    /// <summary>
    /// 消息头长度（4字节，表示消息体长度）
    /// </summary>
    public const int HEADER_SIZE = 4;

    /// <summary>
    /// 消息类型枚举
    /// </summary>
    public enum MessageType : byte
    {
        /// <summary>
        /// 文本消息
        /// </summary>
        Text = 1,

        /// <summary>
        /// 心跳消息
        /// </summary>
        Heartbeat = 2,

        /// <summary>
        /// 确认消息
        /// </summary>
        Ack = 3,

        /// <summary>
        /// 命令消息
        /// </summary>
        Command = 4
    }

    /// <summary>
    /// 消息结构
    /// </summary>
    public class Message
    {
        /// <summary>
        /// 消息类型
        /// </summary>
        public MessageType Type { get; set; }

        /// <summary>
        /// 消息
        /// </summary>
        public byte[] Data { get; set; }

        /// <summary>
        /// 将消息转换为字符串（仅适用于文本消息）
        /// </summary>
        /// <returns></returns>
        public string GetText()
        {
            return Type == MessageType.Text ? Encoding.UTF8.GetString(Data) : null;
        }

        /// <summary>
        /// 从字符串创建文本消息
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static Message CreateText(string text)
        {
            return new Message
            {
                Type = MessageType.Text,
                Data = Encoding.UTF8.GetBytes(text)
            };
        }

        /// <summary>
        /// 创建心跳消息
        /// </summary>
        /// <returns></returns>
        public static Message CreateHeartbeat()
        {
            return new Message
            {
                Type = MessageType.Heartbeat,
                Data = []
            };
        }

        /// <summary>
        /// 创建确认消息
        /// </summary>
        /// <param name="messageId"></param>
        /// <returns></returns>
        public static Message CreateAck(int messageId)
        {
            return new Message
            {
                Type = MessageType.Ack,
                Data = BitConverter.GetBytes(messageId)
            };
        }
    }

    /// <summary>
    /// 序列化消息到字节数组
    /// </summary>
    /// <param name="message">消息</param>
    /// <returns></returns>
    public static byte[] Serialize(Message message)
    {
        // 计算总长度：类型(1字节) + 数据长度 + 头部长度(4字节)
        int totalLength = 1 + message.Data.Length;

        using var ms = new MemoryStream(HEADER_SIZE + totalLength);
        using var writer = new BinaryWriter(ms);
        // 写入消息总长度（不包括头部自身）
        writer.Write(totalLength);

        // 写入消息类型
        writer.Write((byte)message.Type);

        // 写入消息数据
        writer.Write(message.Data);

        return ms.ToArray();
    }

    /// <summary>
    /// 从字节数组解析消息
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="offset"></param>
    /// <param name="count"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static Message Deserialize(byte[] buffer, int offset, int count)
    {
        if (count < HEADER_SIZE + 1) // 至少需要头部+1字节类型
            throw new ArgumentException("Buffer too small to contain a valid message");

        using var ms = new MemoryStream(buffer, offset, count);
        using var reader = new BinaryReader(ms);
        // 读取消息总长度（不包括头部）
        int messageLength = reader.ReadInt32();

        // 验证消息长度
        if (messageLength + HEADER_SIZE != count)
            throw new ArgumentException("Message length mismatch");

        // 读取消息类型
        MessageType type = (MessageType)reader.ReadByte();

        // 读取消息数据
        byte[] data = reader.ReadBytes(messageLength - 1); // 减去类型字节

        return new Message
        {
            Type = type,
            Data = data
        };
    }
}